<script lang="ts" setup>
import {validator} from "@/utils";
import {BaseFormItem} from "./interface";
import {ElDatePicker, ElInput, ElInputNumber, ElRadioGroup, ElSelect, ElTreeSelect} from "element-plus";
import {ComponentPublicInstance, computed, onBeforeMount, Ref, ref, watch} from "vue";

const props = withDefaults(defineProps<BaseFormItem>(), {
    el: 'input',
    required: undefined
});

const formItemRef = ref();

// 组件绑定值
const value = defineModel<any>();

// 校验规则
const rules = (com: ComponentPublicInstance | null) => {
    if (typeof props.required !== 'undefined' && !props.disabled) {
        let rule = com? com.$attrs.rule:'';
        return {required: props.required, trigger: 'blur', group: rule, validator: validator}
    } else {
        return null;
    }
};

const items: string[] = props.el.split(".");
// 组件实例
const component = computed(() => {
    switch (items[0]) {
        case 'select':
            return ElSelect;
        case 'date-picker':
            return ElDatePicker;
        case 'tree':
            return "ElTree";
        case 'tree-select':
            return ElTreeSelect;
        case 'radio-group':
            return ElRadioGroup;
        case 'input':
            return ElInput;
        case 'number':
            return ElInputNumber;
        case 'override':
        default:
            return null;
    }
});
// 组件属性
const attribute = computed(() => {
    const el = items[0];
    const attr = {
        clearable: el.indexOf('select') <= -1,
        placeholder: props.disabled? '':(el.indexOf('select') > -1 ? '请选择' : '请输入') + props.label,
        disabled: props.disabled,
    } as any
    if (["date-picker"].includes(el)) {
        const type = items.length > 1? items[1]:'date';
        attr['type'] = type;
        attr['format'] = type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss';
        attr['valueFormat'] = type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss';
        attr['rangeSeparator'] = "至";
        attr['startPlaceholder'] = "开始时间";
        attr['endPlaceholder'] = "结束时间";
    } else if (["select"].includes(el)) {
        for (let i = 1; i < items.length; i++) {
            attr[items[i]] = true;
        }
        attr['filterable'] = true;
        attr['reserveKeyword'] = false;
        attr['collapseTags'] = true;
        attr['collapseTagsTooltip'] = true;
        attr['maxCollapseTags'] = 3;
    } else if (["tree-select"].includes(el)) {
        for (let i = 1; i < items.length; i++) {
            attr[items[i]] = true;
        }
        attr['nodeKey'] = 'id';
        attr['accordion'] = true;
        attr['expandOnClickNode'] = true;
    } else if ("tree" === el) {
        attr['height'] = '30vh';
        attr['nodeKey'] = 'id';
        attr['accordion'] = true;
        attr['checkStrictly'] = true;
        attr['showCheckbox'] = true
        attr['checkOnClickNode'] = true;
        attr['expandOnClickNode'] = false;
        attr['onCheckChange'] = () => {
            let checked = formItemRef.value?.getCheckedKeys(false);
            let halfChecked = formItemRef.value?.getHalfCheckedKeys();
            value.value = [...checked, ...halfChecked]
        };
    }
    return Object.assign(attr, props.attrs);
});
// 选项集合
const options = computed(() => props.option);

// 请求动态数据
const datasource = ref<any[]>([]);
onBeforeMount(async () => {
    //适用tree/tree-select组件加载data数据
    if (typeof props.data === 'object' && Array.isArray(props.data)) {
        datasource.value = props.data;
    } else if (typeof props.data === 'function') {
        props.data((data: any): Promise<Ref> => {
            datasource.value = data;
            return new Promise(resolve => resolve(formItemRef));
        }, props.prop);
    }
})

let checkedKeys: any[];
if (items[0] === 'tree') {
    const stopWatch = watch(()=> value.value, (v) => {
        if (checkedKeys === undefined) {
            checkedKeys = v;
            stopWatch();
        }
    });
}
</script>

<template>
    <el-form-item v-if="label" :label="label" :prop="prop" :rules="rules($parent)">
        <el-scrollbar v-if="component === 'ElTree'" :height="attribute['height']" style="width: 100%">
            <el-tree ref="formItemRef" :data="datasource" v-bind="attribute" :default-checked-keys="checkedKeys"/>
        </el-scrollbar>
        <component v-else-if="component" :is="component" ref="formItemRef" v-model.trim="value" :data="datasource" v-bind="attribute" style="width: 100%">
            <template v-if="el.indexOf('select') === 0">
                <el-option v-for="(item, index) in options" :key="index" v-bind="item">
                    <span style="float: left">{{item.label}}</span>
                    <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px; margin-left: 150px" v-if="!!item.title">
                        {{ item.title }}
                    </span>
                </el-option>
            </template>
            <template v-else-if="el.indexOf('radio-group') === 0">
                <el-radio v-for="(item, index) in options" :key="index" :value="item.value">{{ item.label }}</el-radio>
            </template>
            <slot v-else :options="options"></slot>
        </component>
        <slot v-else :options="options"></slot>
    </el-form-item>
    <el-form-item v-else v-show="false" :prop="prop">
        <el-input v-model="value"/>
    </el-form-item>
</template>